package source.Objetos 
{
    import flash.geom.Point;
	
    import net.flashpunk.graphics.Spritemap;
    import net.flashpunk.Sfx;
    import net.flashpunk.utils.Input;
	
    import source.Assets;
    import source.Global;
	
	public class PJ extends Physics {
        //assets:
		public const sprite:Spritemap = new Spritemap(Assets.PJ, Global.anchoSpritePJ, Global.altoSpritePJ, animEnd);
        public const sfxDisparo:Sfx = new Sfx(Assets.SFX_DISPARO);
        public const sfxSalto:Sfx = new Sfx(Assets.SFX_SALTO);
        public const sfxDobleSalto:Sfx = new Sfx(Assets.SFX_DOBLESALTO);
        public const sfxMuerte:Sfx = new Sfx(Assets.SFX_MUERTE);
        public const sfxPasos:Array = new Array(new Sfx(Assets.SFX_PASO1),
                                             new Sfx(Assets.SFX_PASO2),
                                             new Sfx(Assets.SFX_PASO3),
                                             new Sfx(Assets.SFX_PASO4),
                                             new Sfx(Assets.SFX_PASO5),
                                             new Sfx(Assets.SFX_PASO6));
		
		//how fast we accelerate
		public var movement:Number = 0.8;  //ojo con esto, no sé qué es
		public var jump:Number = 12;       //ojo con esto, no sé qué es
        
		//poderes básicos:
		public var caminar:Boolean = true;
		public var salto:Boolean = true;
		public var interactuar:Boolean = true;
		public var agacharse:Boolean = true;
		
		//poderes desbloqueables:
		public var correr:Boolean = false;
		public var dobleSalto:Boolean = false;
		public var caminaragachado:Boolean = false;
		public var disparar:Boolean = false;
		public var nadar:Boolean = false;
		public var empujar:Boolean = false;
		public var golpeDescendente:Boolean = false;
		
		//otros:		
		public var direction:Boolean = true;                     //current player direction (true = right, false = left)
		public var onground:Boolean = false;                     //are we on the ground?
		public var doblesaltodisponible:Boolean = true;          //are we doublejumped?
        public var timerDisparo:uint = Global.cadenciaDisparo;   //cuando el timer llegue a 0, podremos volver a disparar
        public var timerSfxPaso:uint = Global.periodoSfxCaminar; //cuando el timer llegue a 0, se podrá volver a reproducir el sonido de un paso
		public var muerto:Boolean = false;
		public var paralizado:Boolean = false;
		public var proyectil:Proyectil;
		
        /**
         * Constructor
         * @param	x
         * @param	y
         */
		public function PJ(x:int = 0, y:int = 0) {
            //control de bucles:
            var i:int;
            
			//set position
			super(x, y);
			
			//NOTA: la gravedad y las velocidades máximas se configuran en el método update().
			
			//configuramos las animaciones:
			const frameRateEnPie:Number = 0.05;
			const frameRateCaminar:Number = 0.18;
			const frameRateReptar:Number = 0.2;
			const frameRateAtaque:Number = 0.2;
			const frameRateEscaleras:Number = 0.2;
			const frameRateEmpujar:Number = 0.2;
            
			sprite.add("enPieDch", [4, 4, 4, 5], frameRateEnPie, true);
            sprite.add("enPieIzq", [68, 68, 68, 69], frameRateEnPie, true);
			sprite.add("caminarDch", [12, 13, 14, 15], frameRateCaminar, true);
			sprite.add("caminarIzq", [76, 77, 78, 79], frameRateCaminar, true);
            
			sprite.add("saltarDch", [20], 0, false);
			sprite.add("saltarIzq", [84], 0, false);
			sprite.add("saltoDobleDch", [21], 0, false);
			sprite.add("saltoDobleIzq", [85], 0, false);
            
			sprite.add("enPieDch_arco", [0, 0, 0, 1], frameRateEnPie, true);
            sprite.add("enPieIzq_arco", [64, 64, 64, 65], frameRateEnPie, true);
			sprite.add("caminarDch_arco", [8, 9, 10, 11], frameRateCaminar, true);
			sprite.add("caminarIzq_arco", [72, 73, 74, 75], frameRateCaminar, true);
            
			sprite.add("saltarDch_arco", [16], 0, false);
			sprite.add("saltarIzq_arco", [80], 0, false);
			sprite.add("saltoDobleDch_arco", [17], 0, false);
			sprite.add("saltoDobleIzq_arco", [81], 0, false);
            
			sprite.add("agachadoDch", [24], 0, false);
			sprite.add("agachadoIzq", [88], 0, false);
			sprite.add("reptarDch", [25, 26], frameRateReptar, true);
			sprite.add("reptarIzq", [89, 90], frameRateReptar, true);
            
            sprite.add("golpeDescendenteDch", [32], 0, false);
            sprite.add("golpeDescendenteIzq", [96], 0, false);
            sprite.add("ataqueDch", [40, 41], frameRateAtaque, true);
            sprite.add("ataqueIzq", [104, 105], frameRateAtaque, true);
            
            sprite.add("escalerasDch", [48, 49], frameRateEscaleras, true);
            sprite.add("escalerasIzq", [112, 113], frameRateEscaleras, true);
            sprite.add("empujarDch", [56, 57, 58], frameRateEmpujar, true);
            sprite.add("empujarIzq", [120, 121, 122], frameRateEmpujar, true);
            sprite.add("muerto", [32], 0, false);
			
			//set hitbox & graphic:
			setHitbox(Global.anchoHitboxPJ, Global.altoHitboxPJ, Global.offsetXHitboxPJ, Global.offsetYHitboxPJ);
			graphic = sprite;
			type = "PJ";
		}
        
		/**
		 * update
		 */
		override public function update():void {
			//hemos... muerto?
			if (muerto || Global.salirPantalla_porTeletransporte) {
				sprite.alpha -= 0.1;
				return;
			}
			else if (sprite.alpha < 1)
				sprite.alpha += 0.1;
                
            //si estamos paralizados...
			if (paralizado)	{
                animar(); //colocamos la animación correspondiente
                return;   //terminamos la ejecución de este método
            }
			
			//Gestión del agua, gravedad, aceleración y velocidad máxima según habilidad de correr y si el pj está en el agua:
			if (collide("Agua", x, y)) {
                if (nadar) {
                    if (correr) mMaxspeed = Global.maxVelCorrer_enAgua;
                    else mMaxspeed = Global.maxVelCaminar_enAgua;
                    mGravity = Global.gravedad_enAgua;
                }
				else
                    morir();
			}
			else {
				if (correr) mMaxspeed = Global.maxVelCorrer_enAire;
				else mMaxspeed = Global.maxVelCaminar_enAire;
				mGravity = Global.gravedad_enAire;
			}
			
			//estamos en el suelo?
			onground = false;
			if (collide(solid, x, y + 1)) {
				onground = true;
				doblesaltodisponible = true;
			}
			
			acceleration.x = 0; //set acceleration to nothing
			
			//increase acceeration, if we're not going too fast
			if (Input.check("Izq") && speed.x > -mMaxspeed.x && !paralizado) {
				acceleration.x = -movement;
				direction = false;
			}
			else if (Input.check("Dch") && speed.x < mMaxspeed.x && !paralizado) {
				acceleration.x = movement;
				direction = true;
			}
            
            //Reproducimos los sonidos de caminar/correr:
            if (!timerSfxPaso) {
                if ((Input.check("Izq") || Input.check("Dch")) && onground && !collide("Agua", x, y)) {
                    if (!correr) timerSfxPaso = Global.periodoSfxCaminar;
                    else timerSfxPaso = Global.periodoSfxCorrer;
                    if (!sfxPasos[0].playing && !sfxPasos[1].playing && !sfxPasos[2].playing &&
                        !sfxPasos[3].playing && !sfxPasos[4].playing && !sfxPasos[5].playing)
                        sfxPasos[Global.numAleat(0, 5)].play();
                }
            }
            else
                timerSfxPaso--;
			
			//friction (apply if we're not moving, or if our speed.x is larger than maxspeed):
			if ( (!Input.check("Izq") && !Input.check("Dch")) || Math.abs(speed.x) > mMaxspeed.x )
                friction(true, false);
			
			//normal and double jump:		
			if (Input.pressed("Salto")) {
				if (onground) { //normal jump
                    speed.y = -jump;
                    if (!collide("Agua", x, y)) sfxSalto.play();
                }
				else if (!onground && doblesaltodisponible && dobleSalto) { //double jump
					speed.y = -jump;
					doblesaltodisponible = false;
                    if (!collide("Agua", x, y)) {
                        sfxSalto.stop();
                        sfxDobleSalto.play();
                    }
				} 
			}
			
			//disparo:
            if (disparar) {
                if (!timerDisparo) {
                    if (Input.pressed("Disparo") && direction) {
                        timerDisparo = Global.cadenciaDisparo;
                        world.add(proyectil = new Proyectil(x + width - originX + speed.x + 1,        //posicionamos el proyectil, se mueva o no el PJ, justo a su derecha
                                                            y + height + Global.proyectilPJ_altura,   //posicionamos el proyectil en la parte inferior del tile superior del PJ
                                                            Global.proyectilPJ_velocidad.x + speed.x, //el módulo del vector velocidad que tendrá el proyectil
                                                            0,                                        //el argumento del vector velocidad
                                                            Global.proyectilPJ_tieneMasa,             //si le afecta la gravedad o no
                                                            true,                                     //indicamos que es un proyectil perteneciente al PJ
                                                            "pj"));                                   //especificamos el gráfico del proyectil
                        sfxDisparo.play();
                    }
                    else if (Input.pressed("Disparo") && !direction) {
                        timerDisparo = Global.cadenciaDisparo;
                        world.add(proyectil = new Proyectil(x - width - originX + speed.x - 1,         //posicionamos el proyectil, se mueva o no el PJ, justo a su izquierda
                                                            y + height + Global.proyectilPJ_altura,    //posicionamos el proyectil más o menos hacia la mitad de la altura del PJ
                                                            Global.proyectilPJ_velocidad.x - speed.x,  //el módulo del vector velocidad que tendrá el proyectil
                                                            180,                                       //el argumento del vector velocidad
                                                            Global.proyectilPJ_tieneMasa,              //si le afecta la gravedad o no
                                                            true,                                      //indicamos que es un proyectil perteneciente al PJ
                                                            "pj"));                                    //especificamos el gráfico del proyectil
                        sfxDisparo.play();
                    }
                }
                else timerDisparo--;
            }
            
            //golpe descendente:
            if (Input.check("GolpeDescendente") && !Input.check("Salto") && !onground && golpeDescendente) {
                //establecemos una velocidad descendente constante mientras se haga uso de esta habilidad:
                if (collide("Agua", x, y)) speed.y = Global.velGolpeDescendente_enAgua;
                else speed.y = Global.velGolpeDescendente_enAire;
                //NOTA: La gestión de la colisión con el bloque (para que se rompa con esta habilidad) se realiza en la clase Bloque
            }
			
			//suicidio:
			if (Input.pressed("Suicidio")) morir();
			
			//set the gravity
			gravity();
			
			//make sure we're not going too fast vertically
			//the reason we don't stop the player from moving too fast left/right is because
			//that would (partially) destroy the walljumping. Instead, we just make sure the player,
			//using the arrow keys, can't go faster than the max speed, and if we are going faster
			//than the max speed, descrease it with friction slowly.
			maxspeed(false, true);
			
			//variable jumping (tripple gravity)
			if (speed.y < 0 && !Input.check("Salto")) {
				gravity();
				gravity();
			}
			
			
			//reproducimos la animación que toque:
			animar();
			
			//set the motion. We set this later so it stops all movement if we should be stopped
			motion();
			
			//Muerte por pinchos (el pj morirá sólo si se está moviendo hacia los pinchos):
			if (collide("puas_n", x, y) && speed.y < 0) morir();
			if (collide("puas_e", x, y) && speed.x > 0) morir();
			if (collide("puas_s", x, y) && speed.y > 0) morir();
			if (collide("puas_o", x, y) && speed.x < 0) morir();
            
			//Muerte por pinchos:
			if (collide("pinchos", x, y)) morir();
            
			//Muerte por enemigo que tiene la propiedad "muerte al contacto" (los que no la tienen tienen type="EnemigoInofensivo"):
			if (collide("Enemigo", x + 1, y) ||
                collide("Enemigo", x - 1, y) ||
                collide("Enemigo", x, y + 1) ||
                collide("Enemigo", x, y - 1))
                morir();
                
			//Muerte por proyectil enemigo (los proyectiles del PJ tienen type="ProyectilPJ"):
			if (collide("Proyectil", x + 1, y) ||
                collide("Proyectil", x - 1, y) ||
                collide("Proyectil", x, y + 1) ||
                collide("Proyectil", x, y - 1))
                morir();
				
			//Muerte por deathtile:
			if (collide("muerte", x, y)) morir();
			
		}
        
        /**
         * animar
         * gestiona las animaciones del PJ según las condiciones en que se encuentre
         */
        public function animar():void {
            if (paralizado) {
				if (onground) {
                    if (disparar) {
                        if (direction) sprite.play("enPieDch_arco");
                        else sprite.play("enPieIzq_arco");
                    }
                    else {
                        if (direction) sprite.play("enPieDch");
                        else sprite.play("enPieIzq");
                    }
                }
                else if (doblesaltodisponible) {
                    if (disparar) {
                        if (direction) sprite.play("saltarDch_arco");
                        else sprite.play("saltarIzq_arco");
                    }
                    else {
                        if (direction) sprite.play("saltarDch");
                        else sprite.play("saltarIzq");
                    }
                }
                else {
                    if (disparar) {
                        if (direction) sprite.play("saltoDobleDch_arco");
                        else sprite.play("saltoDobleIzq_arco");
                    }
                    else {
                        if (direction) sprite.play("saltoDobleDch");
                        else sprite.play("saltoDobleIzq");
                    }
                }
			}
            else {
                if (onground) {
                    if (speed.x < 0) {
                        if (disparar) sprite.play("caminarIzq_arco");
                        else sprite.play("caminarIzq");
                    }
                    else if (speed.x > 0) {
                        if (disparar) sprite.play("caminarDch_arco");
                        else sprite.play("caminarDch");
                    }
                    else {
                        if (Input.check("Agacharse")) {
                            if (direction) sprite.play("agachadoDch");
                            else sprite.play("agachadoIzq");
                        }
                        else if (disparar) {
                            if (direction) sprite.play("enPieDch_arco");
                            else sprite.play("enPieIzq_arco");
                        }
                        else {
                            if (direction) sprite.play("enPieDch");
                            else sprite.play("enPieIzq");
                        }
                    }
                }
                else if (Input.check("GolpeDescendente") && !Input.check("Salto") && !onground && golpeDescendente) {
                    if (direction) sprite.play("golpeDescendenteDch");
                    else sprite.play("golpeDescendenteIzq");
                }
                else if (doblesaltodisponible) {
                    if (disparar) {
                        if (direction) sprite.play("saltarDch_arco");
                        else sprite.play("saltarIzq_arco");
                    }
                    else {
                        if (direction) sprite.play("saltarDch");
                        else sprite.play("saltarIzq");
                    }
                }
                else {
                    if (disparar) {
                        if (direction) sprite.play("saltoDobleDch_arco");
                        else sprite.play("saltoDobleIzq_arco");
                    }
                    else {
                        if (direction) sprite.play("saltoDobleDch");
                        else sprite.play("saltoDobleIzq");
                    }
                }
            }
        }
		
        /**
         * morir
         * Es llamada cuando el PJ se suicida o muere de cualquier modo
         */
		public function morir():void {
			Global.pj.speed.x = 0;
			Global.pj.speed.y = 0;
			muerto = true;
			Global.respawn = true;
            sfxMuerte.play();
		}
        
        /**
         * resetear
         * Resetea todas las propiedades del PJ relativas a la jugabilidad
         */
		public function resetear():void {
            //reseteo de los poderes desbloqueables:
            correr = false;
            dobleSalto = false;
            caminaragachado = false;
            disparar = false;
            nadar = false;
            empujar = false;
            golpeDescendente = false;
		}
		
        /**
         * animEnd
         * Se llamará a esta función al terminar cualquier animación:
         */
		public function animEnd():void { }
	}
}